home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.09 Sep 95 / 11.09 Challenge Winner-Sprite.c next >
Encoding:
C/C++ Source or Header  |  1995-07-05  |  15.9 KB  |  692 lines  |  [TEXT/R*ch]

  1. /*        Sprite Blitz Solution by Xan Gregg, July 1995
  2. Since "correctness" is considered before speed in judging
  3. solutions, this solution makes correctness the top priority
  4. at the cost of speed.
  5.  
  6. I use two offscreen GWorlds.  One has the background, and
  7. another has the image to be displayed on the screen next.
  8. The "on deck" image is updated sprite by sprite, then it is
  9. copied to the screen for minimum flicker.
  10.  
  11. The GWorlds are a little bigger than the screen so I don't
  12. have to worry about sprites that overlap the edges until
  13. copying to the screen.
  14.  
  15. Memory usage:
  16.     2 GWorlds, each 64 pixels wider and taller than window.
  17.     1K of pixel data for each sprite.
  18.     128 bytes of mask data for each sprite.
  19.     16 bytes of info for each sprite.
  20. I set the number of sprites to 400.  The problem states a
  21. maximum of 200 present at a time, but because a deleted
  22. sprite stays around until the next UpdateScreen() call,
  23. I allow for 400 in case you delete all 200 then add 200
  24. more before calling UpdateScreen().  Paranoid, but if
  25. you've got the memory...
  26.  
  27. Assumptions not stated in the problem:
  28.     Enough memory available for above usage.
  29.     Window width is a multiple of 4 (confirmed by BB).
  30.     Window does not move during play.
  31.  
  32. */
  33.  
  34. #include <QDOffscreen.h>
  35. /*#include "July.h"        /* prototypes */
  36.  
  37. typedef struct
  38.  {
  39.     short        nextSlot;
  40.     short        status;
  41.     short        width;
  42.     short        height;
  43.     Point        position;
  44.     Point        lastPosition;
  45.  } SpriteInfo, *SpriteInfoPtr;
  46.  
  47. typedef struct
  48.  {
  49.     char    pixData[1024];
  50.  } SpritePixData, *SpritePixDataPtr;
  51.  
  52. typedef struct
  53.  {
  54.     char    maskData[128];
  55.  } SpriteMaskData, *SpriteMaskDataPtr;
  56.  
  57.  
  58. #define kMaxSprites            400L
  59. #define kMaxSpriteWidth        32L
  60. #define kMaxSpriteHeight    32L
  61.  
  62. static CWindowPtr    gScreenWindowP;
  63. static GWorldPtr    gBackgroundGW;
  64. static PixMapHandle    gBackgroundPixMapH;
  65. static GWorldPtr    gOnDeckGW;
  66. static PixMapHandle    gOnDeckPixMapH;
  67. static short        gLastSpriteSlot;
  68. static short        gFirstSpriteSlot;
  69. static short        gSpriteCount;
  70. static short        gWindowWidth;
  71. static short        gWindowHeight;
  72. static SpriteInfoPtr gSpriteInfo;
  73. static SpritePixDataPtr gSpritePixData;
  74. static SpriteMaskDataPtr gSpriteMaskData;
  75. static long            gOnDeckRowBytes;
  76. static Ptr            gOnDeckBaseAddr;
  77. static long            gBkgRowBytes;
  78. static Ptr            gBkgBaseAddr;
  79. static long            gScreenRowBytes;
  80. static Ptr            gScreenBaseAddr;
  81. static Ptr            *gBkgRowAddr;
  82. static Ptr            *gOnDeckRowAddr;
  83. static Ptr            *gScreenRowAddr;
  84. static short        gDeletionCount;
  85.  
  86.  
  87.  
  88.  
  89. void StartGame(CWindowPtr windowP)
  90. {
  91.     Rect        r;
  92.     PixMapPtr    bkgPixMapP;
  93.     PixMapPtr    onDeckPixMapP;
  94.     PixMapPtr    screenPixMapP;
  95.     
  96.     gLastSpriteSlot = -1;
  97.     gFirstSpriteSlot = -1;
  98.     gSpriteCount = 0;
  99.     gDeletionCount = 0;
  100.     gScreenWindowP = windowP;
  101.     r = windowP->portRect;
  102.     OffsetRect(&r, -r.left, -r.top);
  103.     gWindowWidth = r.right;
  104.     gWindowHeight = r.bottom;
  105.  
  106.     InsetRect(&r, -kMaxSpriteWidth, -kMaxSpriteHeight);
  107.     NewGWorld(&gBackgroundGW, 0, &r, 0, 0, 0);
  108.     gBackgroundPixMapH = GetGWorldPixMap(gBackgroundGW);
  109.     LockPixels(gBackgroundPixMapH);    /* always locked */
  110.     NewGWorld(&gOnDeckGW, 0, &r, 0, 0, 0);
  111.     gOnDeckPixMapH = GetGWorldPixMap(gOnDeckGW);
  112.     LockPixels(gOnDeckPixMapH);        /* always locked */
  113.     
  114.     gSpriteInfo = (SpriteInfoPtr) NewPtrClear
  115.                 (sizeof(SpriteInfo) * kMaxSprites);
  116.     gSpritePixData = (SpritePixDataPtr) NewPtrClear
  117.                 (sizeof(SpritePixData) * kMaxSprites);
  118.     gSpriteMaskData = (SpriteMaskDataPtr) NewPtrClear
  119.                 (sizeof(SpriteMaskData) * kMaxSprites);
  120.     gBkgRowAddr = (Ptr *) NewPtr(sizeof(Ptr) *
  121.                 (gWindowHeight + kMaxSpriteHeight * 2));
  122.     gOnDeckRowAddr = (Ptr *) NewPtr(sizeof(Ptr) *
  123.                 (gWindowHeight + kMaxSpriteHeight * 2));
  124.     gScreenRowAddr = (Ptr *) NewPtr(sizeof(Ptr)
  125.                                 * (long) gWindowHeight);
  126.     if (gSpriteInfo == 0 || gSpritePixData == 0
  127.             || gSpriteMaskData == 0 || gScreenRowAddr == 0
  128.             || gBkgRowAddr == 0 || gOnDeckRowAddr == 0
  129.             || gBackgroundGW == 0 || gOnDeckGW == 0)
  130.         DebugStr("\p out of memory!");
  131.     InsetRect(&r, kMaxSpriteWidth, kMaxSpriteHeight);
  132.     OffsetRect(&r, kMaxSpriteWidth, kMaxSpriteHeight);
  133.     CopyBits(&((WindowPtr)windowP)->portBits,
  134.                 &((WindowPtr)gBackgroundGW)->portBits,
  135.                 &windowP->portRect, &r, srcCopy, NULL);
  136.     CopyBits(&((WindowPtr)windowP)->portBits,
  137.                 &((WindowPtr)gOnDeckGW)->portBits,
  138.                 &windowP->portRect, &r, srcCopy, NULL);
  139.                 
  140.     bkgPixMapP = *gBackgroundPixMapH;
  141.     onDeckPixMapP = *gOnDeckPixMapH;
  142.     gOnDeckRowBytes = onDeckPixMapP->rowBytes & 0x7fff;
  143.     gOnDeckBaseAddr = onDeckPixMapP->baseAddr
  144.                     + gOnDeckRowBytes * kMaxSpriteHeight
  145.                     + kMaxSpriteWidth;
  146.     gBkgRowBytes = bkgPixMapP->rowBytes & 0x7fff;
  147.     gBkgBaseAddr = bkgPixMapP->baseAddr
  148.                     + gBkgRowBytes * kMaxSpriteHeight
  149.                     + kMaxSpriteWidth;
  150.     screenPixMapP = *gScreenWindowP->portPixMap;
  151.     gScreenRowBytes = screenPixMapP->rowBytes & 0x7fff;
  152.     gScreenBaseAddr = screenPixMapP->baseAddr
  153.                     - screenPixMapP->bounds.left
  154.                     - screenPixMapP->bounds.top
  155.                          * gScreenRowBytes;
  156.     
  157.     {    /* initialize rowAddr's */
  158.     long    row;
  159.     
  160.     gOnDeckRowAddr += kMaxSpriteHeight;
  161.     gBkgRowAddr += kMaxSpriteHeight;
  162.     for (row = -kMaxSpriteHeight;
  163.             row < gWindowHeight + kMaxSpriteHeight; row++)
  164.      {
  165.         gBkgRowAddr[row] = gBkgBaseAddr
  166.                                 + row * gBkgRowBytes;
  167.         gOnDeckRowAddr[row] = gOnDeckBaseAddr
  168.                                 + row * gOnDeckRowBytes;
  169.      }
  170.     for (row = 0; row < gWindowHeight; row++)
  171.         gScreenRowAddr[row] = gScreenBaseAddr
  172.                                 + row * gScreenRowBytes;
  173.     }
  174. }
  175.  
  176.  
  177. /* make a copy of CIcon's pixel and mask data */
  178. short AddSprite(CIconPtr cIconP, Point startPt)
  179. {
  180.     short    slot;
  181.     short    i;
  182.     short    pixWidth;
  183.     short    maskWidth;
  184.     short    pixBytes;
  185.     short    maskBytes;
  186.     short    bitBytes;
  187.     short    height;
  188.     Ptr        pixSrcAddr, pixDstAddr;
  189.     long    *maskSrcAddr, *maskDstAddr;
  190.     
  191.     slot = gLastSpriteSlot + 1;
  192.     if (slot == kMaxSprites)
  193.         slot = 0;
  194.     while (gSpriteInfo[slot].status != 0)
  195.      {
  196.         slot++;
  197.         if (slot == kMaxSprites)
  198.             slot = 0;
  199.      }
  200.     gSpriteInfo[slot].status = 1;    /* occupied */
  201.     height = cIconP->iconPMap.bounds.bottom
  202.                     - cIconP->iconPMap.bounds.top;
  203.     pixWidth = cIconP->iconPMap.bounds.right
  204.                     - cIconP->iconPMap.bounds.left;
  205.     maskWidth = (pixWidth + 7) >> 3;
  206.     gSpriteInfo[slot].width = pixWidth;
  207.     gSpriteInfo[slot].height = height;
  208.     pixBytes = cIconP->iconPMap.rowBytes & 0x7fff;
  209.     maskBytes = cIconP->iconMask.rowBytes;
  210.     bitBytes = cIconP->iconBMap.rowBytes;
  211.     pixSrcAddr = ((Ptr) &cIconP->iconMaskData)
  212.             + bitBytes * height
  213.             + maskBytes * height
  214.             + 256 * 8 + 8;    /* 8-bit color table */
  215.  
  216.     pixDstAddr = (char *) &gSpritePixData[slot];
  217.     maskSrcAddr = (long *) &cIconP->iconMaskData;
  218.     maskDstAddr = (long *) &gSpriteMaskData[slot];
  219.     pixWidth = pixWidth >> 2;
  220.     for (i = 0; i < height; i++)
  221.      {
  222.         {
  223.         register long    *q = (long *) pixDstAddr;
  224.         register long    *p = (long *) pixSrcAddr;
  225.         register short    j = pixWidth;
  226.         while (j > 0)
  227.          {
  228.             *q++ = *p++;
  229.             j--;
  230.          }
  231.         }
  232.         *maskDstAddr++ = *maskSrcAddr;
  233.         pixDstAddr += 32;
  234.         pixSrcAddr += pixBytes;
  235.         maskSrcAddr = (long *) (((Ptr) maskSrcAddr)
  236.                         + maskBytes);
  237.      }
  238.     
  239.     if (gLastSpriteSlot >= 0)
  240.      {
  241.         gSpriteInfo[gLastSpriteSlot].nextSlot = slot;
  242.      }
  243.     else
  244.      {
  245.         gFirstSpriteSlot = slot;
  246.      }
  247.     gLastSpriteSlot = slot;
  248.     gSpriteInfo[slot].nextSlot = -1;
  249.     gSpriteInfo[slot].position = startPt;
  250.     gSpriteInfo[slot].lastPosition = startPt;
  251.     gSpriteCount ++;
  252.     return slot;
  253. }
  254.  
  255.  
  256. /* replace sprite with chunk from the bkg gworld */
  257. static void EraseSprite(SpriteInfoPtr spriteInfoP)
  258. {
  259.     short            numRows;
  260.     short            numCols;
  261.     register long    *p;
  262.     register long    *q;
  263.     short            h, v;
  264.     register long    srcRowBytes;
  265.     register long    dstRowBytes;
  266.     
  267.     numRows = spriteInfoP->height;
  268.     numCols = spriteInfoP->width;
  269.     h = spriteInfoP->lastPosition.h;
  270.     v = spriteInfoP->lastPosition.v;
  271.     if (h + numCols <= 0 || h >= gWindowWidth
  272.         || v + numRows <= 0 || v >= gWindowHeight)
  273.         return;    /* totally offscreen, so skip it */
  274.     
  275.     p = (long *) (gBkgRowAddr[v] + h);
  276.     q = (long *) (gOnDeckRowAddr[v] + h);
  277.     srcRowBytes = gBkgRowBytes - numCols;
  278.     dstRowBytes = gOnDeckRowBytes - numCols;
  279.     if (numCols >= 16)
  280.         if (numCols == 32)
  281.          {
  282.             while (numRows != 0)
  283.              {
  284.                 numRows--;
  285.                 *q++ = *p++;
  286.                 *q++ = *p++;
  287.                 *q++ = *p++;
  288.                 *q++ = *p++;
  289.                 *q++ = *p++;
  290.                 *q++ = *p++;
  291.                 *q++ = *p++;
  292.                 *q++ = *p++;
  293.                 p = (long *) (((Ptr) p) + srcRowBytes);
  294.                 q = (long *) (((Ptr) q) + dstRowBytes);
  295.              }
  296.          }
  297.         else
  298.          {
  299.             while (numRows != 0)
  300.              {
  301.                 numRows--;
  302.                 *q++ = *p++;
  303.                 *q++ = *p++;
  304.                 *q++ = *p++;
  305.                 *q++ = *p++;
  306.                 p = (long *) (((Ptr) p) + srcRowBytes);
  307.                 q = (long *) (((Ptr) q) + dstRowBytes);
  308.              }
  309.          }
  310.     else
  311.      {
  312.         if (numCols < 8)
  313.             while (numRows != 0)
  314.              {
  315.                 numRows--;
  316.                 *q = *p;
  317.                 p = (long *) (((Ptr) p) + gBkgRowBytes);
  318.                 q = (long *) (((Ptr) q) + gOnDeckRowBytes);
  319.              }
  320.         else /* erase 4 pixels, even if its smaller */
  321.             while (numRows != 0)
  322.              {
  323.                 numRows--;
  324.                 *q++ = *p++;
  325.                 *q++ = *p++;
  326.                 p = (long *) (((Ptr) p) + srcRowBytes);
  327.                 q = (long *) (((Ptr) q) + dstRowBytes);
  328.              }
  329.      }
  330. }
  331.  
  332.  
  333. /* Don't actually do the delete, just mark for deletion.
  334.     -- because we still need to erase it in UpdateScreen()
  335. */
  336. void DeleteSprite(short spriteID)
  337. {
  338.     gSpriteInfo[spriteID].status = -1;    /* to be deleted */
  339.     gDeletionCount++;
  340. }
  341.  
  342.  
  343. /* only called when there is at least one deletion */
  344. static void RemoveDeletedSprites(void)
  345. {
  346.     short    prevSlot = -1;
  347.     short    slot = gFirstSpriteSlot;
  348.     short    count = gDeletionCount;
  349.     
  350.     while (1)
  351.      {
  352.         if (gSpriteInfo[slot].status < 0)
  353.          {    /* needs to be removed */
  354.             if (prevSlot >= 0)
  355.                 gSpriteInfo[prevSlot].nextSlot
  356.                          = gSpriteInfo[slot].nextSlot;
  357.             else
  358.                 gFirstSpriteSlot
  359.                          = gSpriteInfo[slot].nextSlot;
  360.             if (slot == gLastSpriteSlot)
  361.                 gLastSpriteSlot = prevSlot;
  362.             gSpriteInfo[slot].status = 0;    /* available */
  363.             gSpriteCount--;
  364.             count--;
  365.             if (count == 0)
  366.                 break;
  367.          }
  368.         else
  369.          {
  370.             prevSlot = slot;
  371.          }
  372.         slot = gSpriteInfo[slot].nextSlot;
  373.      }
  374.     gDeletionCount = 0;
  375. }
  376.  
  377.  
  378.  
  379. void MoveSprite(short spriteID, Point deltaPt)
  380. {
  381.     gSpriteInfo[spriteID].position.h += deltaPt.h;
  382.     gSpriteInfo[spriteID].position.v += deltaPt.v;
  383. }
  384.  
  385.  
  386. static void EraseOldSprites(void)
  387. {
  388.     short    slot;
  389.     SpriteInfoPtr    spriteInfoP;
  390.     
  391.     slot = gFirstSpriteSlot;
  392.     while (slot >= 0)
  393.      {
  394.         spriteInfoP = &gSpriteInfo[slot];
  395.         EraseSprite(spriteInfoP);
  396.         slot = spriteInfoP->nextSlot;
  397.      }
  398.     
  399. }
  400.  
  401. /* copy 4 pixels based on bits of the mask */
  402. #define COPY4(q,p,m)                                    \
  403. switch ((m) & 0x0f)                                        \
  404.  {                                                        \
  405.     case 0x0: break;                                    \
  406.     case 0x1: *(q+3) = *(p+3); break;                    \
  407.     case 0x2: *(q+2) = *(p+2); break;                    \
  408.     case 0x3: *(short*)(q+2) = *(short*)(p+2); break;    \
  409.     case 0x4: *(q+1) = *(p+1); break;                    \
  410.     case 0x5: *(q+1) = *(p+1); *(q+3) = *(p+3); break;    \
  411.     case 0x6: *(short*)(q+1) = *(short*)(p+1); break;    \
  412.     case 0x7: *(q+1) = *(p+1);                            \
  413.               *(short*)(q+2) = *(short*)(p+2); break;    \
  414.     case 0x8: *(q) = *(p); break;                        \
  415.     case 0x9: *(q) = *(p); *(q+3) = *(p+3); break;        \
  416.     case 0xA: *(q) = *(p); *(q+2) = *(p+2); break;        \
  417.     case 0xB: *(q) = *(p);                                \
  418.               *(short*)(q+2) = *(short*)(p+2); break;    \
  419.     case 0xC: *(short*)(q) = *(short*)(p); break;        \
  420.     case 0xD: *(short*)(q) = *(short*)(p);                \
  421.               *(q+3) = *(p+3); break;                    \
  422.     case 0xE: *(short*)(q) = *(short*)(p);                \
  423.               *(q+2) = *(p+2); break;                    \
  424.     case 0xF: *(long*)(q) = *(long*)(p); break;            \
  425.  }
  426.  
  427. #define COPY8(q,p,mask)                            \
  428.     COPY4(q, p, mask >> 4)                        \
  429.     COPY4(q+4,p+4, mask)
  430.  
  431.  
  432.  
  433. static void DrawSprite(short slot)
  434. {
  435.     SpriteInfoPtr spriteInfoP;
  436.     short        numRows;
  437.     short        numCols;
  438.     register Ptr    p;
  439.     register Ptr    q;
  440.     Ptr            maskP;
  441.     short        srcRowBytes;
  442.     short        h, v;
  443.     short        mask;
  444.     short        maskMask;
  445.     short        maskRowBytes;
  446.     short        numMaskBytes;
  447.     short        i;
  448.     long        dstRowBytes;
  449.  
  450.     spriteInfoP = &gSpriteInfo[slot];
  451.     h = spriteInfoP->position.h;
  452.     v = spriteInfoP->position.v;
  453.     numRows = spriteInfoP->height;
  454.     numCols = spriteInfoP->width;
  455.     p = (char *) &gSpritePixData[slot];
  456.     q = gOnDeckRowAddr[v] + h;
  457.     maskP = (char *) &gSpriteMaskData[slot];
  458.     
  459.     if (numCols >= 8)
  460.      {
  461.         numMaskBytes = numCols >> 3;
  462.         maskRowBytes = 4 - numMaskBytes;
  463.         srcRowBytes = 40 - numCols;
  464.         dstRowBytes = gOnDeckRowBytes - numCols + 8;
  465.         while (1)
  466.          {
  467.             i = numMaskBytes;
  468.             while (1)
  469.              {
  470.                 mask = *maskP++;
  471.                 COPY8(q, p, mask)
  472.                 if (--i == 0)
  473.                     break;
  474.                 p += 8;
  475.                 q += 8;
  476.              }
  477.             if (--numRows == 0)
  478.                 break;
  479.             maskP += maskRowBytes;
  480.             p += srcRowBytes;
  481.             q += dstRowBytes;
  482.          }
  483.      }
  484.     else
  485.      {
  486.         maskMask = 0xf00 >> numCols;
  487.         while (1)
  488.          {
  489.             mask = (*maskP) & maskMask;
  490.             COPY8(q, p, mask)
  491.             if (--numRows == 0)
  492.                 break;
  493.             maskP += 4;
  494.             p += 32;
  495.             q += gOnDeckRowBytes;
  496.          }
  497.      }
  498. }
  499.  
  500.  
  501. static void DrawNewSprites(void)
  502. {
  503.     register short    slot;
  504.     SpriteInfoPtr    spriteInfoP;
  505.         
  506.     slot = gFirstSpriteSlot;
  507.     while (slot >= 0)
  508.      {
  509.         register short        numRows;
  510.         register short        numCols;
  511.         register short        h;
  512.         register short        v;
  513.         
  514.         spriteInfoP = &gSpriteInfo[slot];
  515.         if (spriteInfoP->status < 0)
  516.             goto nextSlot;    /* deleted, so skip it */
  517.         numRows = spriteInfoP->height;
  518.         numCols = spriteInfoP->width;
  519.         h = spriteInfoP->position.h;
  520.         v = spriteInfoP->position.v;
  521.         if (h + numCols <= 0 || h >= gWindowWidth
  522.             || v + numRows <= 0 || v >= gWindowHeight)
  523.             goto nextSlot;    /* totally offscreen */
  524.  
  525.         DrawSprite(slot);
  526. nextSlot:
  527.         slot = spriteInfoP->nextSlot;
  528.      }
  529. }
  530.  
  531.  
  532. /* count is a multiple of 4 in the range [4..44] */
  533. static void FastCopyChunk(long *q, long *p,
  534.                                 short count, short rows)
  535. {
  536.     register short    srcRowBytes;
  537.     register short    dstRowBytes;
  538.     register short    rowsLeft = rows;
  539.     register short    copy8 = count & 8;
  540.     register short    copy4 = count & 4;
  541.     
  542.     srcRowBytes = gOnDeckRowBytes - count;
  543.     dstRowBytes = gScreenRowBytes - count;
  544.     if (count & 32)
  545.      {
  546.         while (rowsLeft > 0)
  547.          {
  548.             rowsLeft--;
  549.             *q++ = *p++;
  550.             *q++ = *p++;
  551.             *q++ = *p++;
  552.             *q++ = *p++;
  553.             *q++ = *p++;
  554.             *q++ = *p++;
  555.             *q++ = *p++;
  556.             *q++ = *p++;
  557.             if (copy8)
  558.              {
  559.                 *q++ = *p++;
  560.                 *q++ = *p++;
  561.              }
  562.             if (copy4)
  563.                 *q++ = *p++;
  564.             p = (long *) (((Ptr) p) + srcRowBytes);
  565.             q = (long *) (((Ptr) q) + dstRowBytes);
  566.          }
  567.      }
  568.     else if (count & 16)
  569.      {
  570.         while (rowsLeft > 0)
  571.          {
  572.             rowsLeft--;
  573.             *q++ = *p++;
  574.             *q++ = *p++;
  575.             *q++ = *p++;
  576.             *q++ = *p++;
  577.             if (copy8)
  578.              {
  579.                 *q++ = *p++;
  580.                 *q++ = *p++;
  581.              }
  582.             if (copy4)
  583.                 *q++ = *p++;
  584.             p = (long *) (((Ptr) p) + srcRowBytes);
  585.             q = (long *) (((Ptr) q) + dstRowBytes);
  586.           }
  587.      }
  588.     else
  589.      {
  590.         while (rowsLeft > 0)
  591.          {
  592.             rowsLeft--;
  593.             if (copy8)
  594.              {
  595.                 *q++ = *p++;
  596.                 *q++ = *p++;
  597.              }
  598.             if (copy4)
  599.                 *q++ = *p++;
  600.             p = (long *) (((Ptr) p) + srcRowBytes);
  601.             q = (long *) (((Ptr) q) + dstRowBytes);
  602.           }
  603.      }
  604. }
  605.  
  606.  
  607. /* Here we do have to watch out for sprites that overlap
  608. the edges of the window.  We copy a rectangluar region
  609. that includes the sprites previous and current positions.
  610. We know they will be close sionce sprites move at most
  611. 8 pixels per turn.
  612. */
  613. static void DrawNewSpritesToScreen(void)
  614. {
  615.     short            slot;
  616.     SpriteInfoPtr    spriteInfoP;
  617.     short            numRows;
  618.     short            numCols;
  619.     register long    *p;
  620.     register long     *q;
  621.     short            hStart, hEnd;
  622.     short            vStart, vEnd;
  623.         
  624.     slot = gFirstSpriteSlot;
  625.     while (slot >= 0)
  626.      {        
  627.         spriteInfoP = &gSpriteInfo[slot];
  628.         numRows = spriteInfoP->height;
  629.         numCols = spriteInfoP->width;
  630.         if (spriteInfoP->position.h
  631.                      < spriteInfoP->lastPosition.h)
  632.          {
  633.             hStart = spriteInfoP->position.h;
  634.             hEnd = spriteInfoP->lastPosition.h + numCols;
  635.          }
  636.         else
  637.          {
  638.             hStart = spriteInfoP->lastPosition.h;
  639.             hEnd = spriteInfoP->position.h + numCols;
  640.          }
  641.         if (hStart < 0)
  642.             hStart = 0;
  643.         else if (hEnd > gWindowWidth)
  644.             hEnd = gWindowWidth;
  645.         if (spriteInfoP->position.v
  646.                      < spriteInfoP->lastPosition.v)
  647.          {
  648.             vStart = spriteInfoP->position.v;
  649.             vEnd = spriteInfoP->lastPosition.v + numRows;
  650.          }
  651.         else
  652.          {
  653.             vStart = spriteInfoP->lastPosition.v;
  654.             vEnd = spriteInfoP->position.v + numRows;
  655.          }
  656.         if (vStart < 0)
  657.             vStart = 0;
  658.         else if (vEnd > gWindowHeight)
  659.             vEnd = gWindowHeight;
  660.         hStart = hStart & -4;    /* make it a mult of 4 */
  661.         hEnd = (hEnd + 3) & -4;    /* make it a mult of 4 */
  662.         
  663.         p = (long *) (gOnDeckRowAddr[vStart] + hStart);
  664.         q = (long *) (gScreenRowAddr[vStart] + hStart);
  665.         
  666.         vEnd -= vStart;    /* now it's a count */
  667.         hEnd -= hStart;    /* now it's a count */
  668.         if (hEnd >= 0)
  669.             FastCopyChunk(q, p, hEnd, vEnd);
  670.         
  671.         spriteInfoP->lastPosition = spriteInfoP->position;
  672.         slot = spriteInfoP->nextSlot;
  673.      }
  674. }
  675.  
  676.  
  677. void UpdateScreen(void)
  678. {    
  679.     EraseOldSprites();
  680.     DrawNewSprites();
  681.     DrawNewSpritesToScreen();
  682.     if (gDeletionCount != 0)
  683.         RemoveDeletedSprites();
  684. }
  685.  
  686.  
  687.  
  688.  
  689.  
  690.  
  691.  
  692.